﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Globalization;
using System.Security.Permissions;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace CodeSnippet.Options
{
    /// <summary>
    /// Provides an editor for the styles available for formatting.
    /// </summary>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust"), PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
    public class StyleEditor : UITypeEditor
    {
        #region Properties
        /// <summary>
        /// Gets the container representing the type descriptor request.
        /// </summary>
        /// <value>The container.</value>
        protected IContainer Container { get; private set; }
        #endregion Properties

        #region Overrides
        /// <summary>
        /// Gets the editor style used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"></see> method.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Drawing.Design.UITypeEditorEditStyle"></see> value that indicates the style of editor used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"></see> method. If the <see cref="T:System.Drawing.Design.UITypeEditor"></see> does not support this method, then <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"></see> will return <see cref="F:System.Drawing.Design.UITypeEditorEditStyle.None"></see>.
        /// </returns>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that can be used to gain additional context information. </param>
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // Determine if we have a valid context.
            return ((context != null) ? UITypeEditorEditStyle.DropDown : base.GetEditStyle(context));
        }
        /// <summary>
        /// Edits the specified object's value using the editor style indicated by the <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"></see> method.
        /// </summary>
        /// <returns>
        /// The new value of the object. If the value of the object has not changed, this should return the same object it was passed.
        /// </returns>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that can be used to gain additional context information. </param>
        /// <param name="value">The object to edit. </param>
        /// <param name="provider">An <see cref="T:System.IServiceProvider"></see> that this editor can use to obtain services. </param>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // Determine if we have a valid context.
            if (context != null && context.Instance != null && provider != null)
            {
                // Set the container for later use.
                Container = context.Container;

                // Access the Property Browser's UI display service, IWindowsFormsEditorService.
                var edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
                if (edSvc != null)
                {
                    //// Create an instance of the editor UI implementation, which is a control that the Property Browser will display.
                    var editor = new TextBox
                                     {
                                         BorderStyle = BorderStyle.None,
                                         Font = new Font(FontFamily.GenericMonospace, 10f),
                                         Height = 150,
                                         Multiline = true,
                                         ScrollBars = ScrollBars.Both,
                                         WordWrap = false,
                                     };
                    // Pass the current property value to the UI editor control.
                    var text = ((value == null) ? string.Empty : value.ToString());
                    // Get the specific items that were previously selected.
                    var lines = text.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
                    // Trim each line.
                    for (var i = 0; i < lines.Length; i++)
                    {
                        lines[i] = lines[i].Trim();
                    }
                    // Assign the lines of text.
                    editor.Lines = lines;
                    // Clear the selection from the editor.
                    editor.GotFocus += delegate { editor.SelectionStart = editor.SelectionLength = 0; };
                    // Ask the Property Browser to display the UI editor control.
                    edSvc.DropDownControl(editor);
                    // Clean up the lines of text from the editor.
                    for (var i = 0; i < lines.Length; i++)
                    {
                        lines[i] = lines[i].Trim().Replace(";", string.Empty);
                    }
                    // Choose the value and close the UI editor control.
                    text = string.Join("; ", editor.Lines).Trim();
                    // Make sure to always terminate with a semi-colon.
                    value = text.EndsWith(";") ? text : string.Format(CultureInfo.InvariantCulture, "{0};", text);
                    // Return the new property value from the editor.
                    return value;
                }
            }
            // Call the base implementation.
            return base.EditValue(context, provider, value);
        }
        #endregion Overrides
    }
}